#ifndef DATAPROCESSOR_H
#define DATAPROCESSOR_H

#include <QtCore>
#include <QtGui>
#include "Singleton.h"

class DataItem;
class ThreadMapping;
class DataEventItem;
class DataThreadStateItem;
class DataMutexItem;

class DataProcessor : public Singleton<DataProcessor>
{
public:
    DataProcessor();
    
    void process();
    
    QSet<DataItem*> itemsInEventRange(int location, int length) const;
    QSet<DataItem*> itemsInTimeRange(unsigned long long location, unsigned long long length) const;

    double eventEntropyInEventRange(int location, int length) const;
    double eventEntropyInTimeRange(unsigned long long location, unsigned long long length) const;
    
    QString threadName(int id) const;
    
    int totalThreads() const;
    int totalEvents() const;
	
	ThreadMapping* getInterruptThreadMap() { return getThreadMapping(-16); }
	QList<ThreadMapping*> getThreads() const;
	QVector<DataMutexItem*> getMutexes(int threadId) const { return idMutexesMap[threadId]; }
	
	unsigned long long timeForEvent(int event) const { return eventTimeMap[event]; }

protected:
    int floorEventForTime(unsigned long long time) const;
    int ceilEventForTime(unsigned long long time) const;
    
private:
    void compileEventRangeMap();
    void createThread(unsigned long threadPointer, int currentThreadId);
    void updateThreadState(ThreadMapping* threadMap, int eventNr);
    void sleepThread(int threadId);
    void wakeThread(unsigned long awakenedThreadPointer, int currentThreadId);
    void suspendThread(unsigned long suspendedThreadPointer, int currentThreadId);
    void resumeThread(unsigned long resumedThreadPointer, int currentThreadId);
    void changeThreadPriority(unsigned long modifiedThreadPointer, int newPriority);
    void delayThread(unsigned long delayedThreadPointer, int delay, int currentThreadId);
    void checkAlarm(int threadId);
    void enterThread(unsigned long enteredThreadPointer);
    void switchThread(unsigned long currentThreadPointer, unsigned long replacingThreadPointer);
	void startInterruptHandling();

    double calcEventEntropyRating(double eventsPerSec) const;
    ThreadMapping* getThreadMapping(int threadId);
    ThreadMapping* getThreadMapping(unsigned long threadPointer);
    void setThreadState(int threadId, DataThreadStateItem* state);
    void setCurrentRunningThreadId(int threadId);
    void processThreadMapping();
    void processEvents();
    void commitDataEventItem(DataEventItem* item);
    void commitDataThreadStateItem(DataThreadStateItem* item);
    void finalizeThreadState(int threadId);
    void finalizeThreadStates();
	
	void processMutexes();
	void lockMutex(const QString& symbol, int threadId);
	void unlockMutex(const QString& symbol, int threadId);
	void finalizeMutexes();

public:
    unsigned long long nsPerTick;
    unsigned long long psPerHalClock;
    unsigned long long halClocksPerTick;
    
protected:
    DataItem** eventRangeArray;
    unsigned int* eventRangeArrayIndex;
    unsigned int eventRangeArraySize;
    int eventRangeArrayIndexSize;
    
    QMap<unsigned long long, int> timeEventMap;
	QMap<int, unsigned long long> eventTimeMap;
    
    QMap<unsigned long, ThreadMapping*> pointerThreadMapping;
    QMap<int, ThreadMapping*> idThreadMapping;

	QMap<int, QVector<DataMutexItem*> > idMutexesMap;
	
	QMap<int, int> threadSuspendCounter;
	QMap<int, int> threadSleepCounter;

private:
    int currentEventNr;
    int currentRunningThreadId;

    int virtualLastEventNr;

    QMap<int, DataThreadStateItem*> idThreadStateMapping;
    QMap<int, DataItem*> eventRangeMap;
	
	QMap<int, QMap<QString, DataMutexItem*> > idOpenMutexesMap;
	QMap<int, int> idMutexLevelMap;
	
  unsigned long long absoluteTimestampOffset;
	unsigned long long previousAbsoluteTimestamp;
	unsigned long long previousTimestamp;
	unsigned long long previousTick;
};

class ThreadMapping
{
public:
    ThreadMapping(int id, unsigned long pointer = 0, const QString& name = "undefined") : id(id), pointer(pointer), name(name) {}
    
    int id;
    unsigned long pointer;
    QString name;
};

enum DataItemType { DataEventItemType, DataThreadStateItemType, DataMutexItemType };

class DataItem
{
public:
    DataItem(int eventNr);
    virtual ~DataItem() {}
    
    virtual DataItemType type() = 0;
    
public:
    int eventNr;
};

class DataEventItem : public DataItem
{
public:
    DataEventItem(int eventNr, const QString& eventClass, const QString& eventType);
    virtual DataItemType type() { return DataEventItemType; }
    
public:
    QString eventClass;
    QString eventType;
};

class DataThreadStateItem : public DataItem
{
public:
    DataThreadStateItem(ThreadMapping* threadMapping, const QString& state, int eventLocation, int eventLength = 0);
    virtual DataItemType type() { return DataThreadStateItemType; }
	int eventEnd() const { return eventLocation + eventLength; }
    
public:
    ThreadMapping* threadMapping;
    QString state;
    int eventLocation;
    int eventLength;
};

class DataMutexItem : public DataItem
{
public:
    DataMutexItem(const QString& symbol, int level, int eventLocation, int eventLength = 0);
    virtual DataItemType type() { return DataMutexItemType; }
	int eventEnd() const { return eventLocation + eventLength; }
	void setEventEndLocation(int end) { eventLength = end - eventLocation; }
	
public:
    QString symbol;
	int level;
    int eventLocation;
    int eventLength;
};

#endif // DATAPROCESSOR_H
